package com.szholly.plug.form.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.szholly.utils.common.web.IRealPathResolver;
import com.szholly.utils.spring.SpringBeanFactory;
import com.szholly.utils.util.StringUtils;

/**
 * 定义plupload
 */
@Controller
public class PlUploadController {

	@Autowired
	private IRealPathResolver realPathResolver;
	
	private Logger logger = Logger.getLogger(PlUploadController.class);
	
	private static int BUFFER_SIZE = 100;

	/**
	 * 文件上传
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	@SuppressWarnings({ "unchecked" })
	@RequestMapping(value = "/plupload/upload.do")
	@ResponseBody
	public void fileUpload2(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		
		UploadPara uploadPara = (UploadPara) SpringBeanFactory
				.getBean("uploadPara");
		String uploadPath = uploadPara.getUploadPath();
		String savePath = null;
		String saveUrl = null;
		String repositoryPath = null;
		if (StringUtils.IsNullOrSpace(uploadPath)) {
			uploadPath = "temp/upload/";
		}
		uploadPath += "plupload/";
		savePath = realPathResolver.get("/") + uploadPath;
		repositoryPath = savePath + "temp/";
		saveUrl = request.getContextPath() + "/" + uploadPath;

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String ymd = sdf.format(new Date());
		savePath += ymd + "/";
		saveUrl += ymd + "/";

		File dirFile = new File(repositoryPath);
		if (!dirFile.exists()) {
			dirFile.mkdirs();
		}

		dirFile = new File(savePath);
		if (!dirFile.exists()) {
			dirFile.mkdirs();
		}
		
		try {
			boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			if (isMultipart) {
				String fileName = "";
				Integer chunk = 0, chunks = 0;
				DiskFileItemFactory diskFactory = new DiskFileItemFactory();
				// threshold 极限、临界值，即硬盘缓存 1M
				diskFactory.setSizeThreshold(4 * 1024);
				ServletFileUpload upload = new ServletFileUpload(diskFactory);
				// 设置允许上传的最大文件大小（单位MB）
				upload.setSizeMax(1024 * 1048576);
				upload.setHeaderEncoding("UTF-8");
				try {
					List<FileItem> fileList = upload.parseRequest(request);
					Iterator<FileItem> it = fileList.iterator();
					while (it.hasNext()) {
						FileItem item = it.next();
						String name = item.getFieldName();
						InputStream input = item.getInputStream();
						if ("name".equals(name)) {
							fileName = Streams.asString(input);
							continue;
						}
						if ("chunk".equals(name)) {
							chunk = Integer.valueOf(Streams.asString(input));
							continue;
						}
						if ("chunks".equals(name)) {
							chunks = Integer.valueOf(Streams.asString(input));
							continue;
						}
						if(StringUtils.IsNullOrEmpty(fileName)){
							fileName = item.getName();
						}
						
						// 处理上传文件内容
						if (!item.isFormField()) {
							// 目标文件
							File destFile = new File(savePath, fileName);
							// 文件已存在删除旧文件（上传了同名的文件）
							if (chunk == 0 && destFile.exists()) {
								destFile.delete();
								destFile = new File(savePath, fileName);
							}
							// 合成文件
							appendFile(input, destFile);
							if (chunk == chunks - 1 || !it.hasNext()) {
								logger.info("上传完成");
								response.getWriter().write(
										"{\"status\":true,\"newName\":\"" + saveUrl
												+ fileName + "\"}");
							} else {
								logger.info("还剩[" + (chunks - 1 - chunk) + "]个块文件");
							}
						}
					}
				} catch (FileUploadException ex) {
					response.getWriter().write("{\"status\":false}");
					logger.warn("上传文件失败：" + ex.getMessage());
					return;
				}
			}
		} catch (IOException e) {
			response.getWriter().write("{\"status\":false}");
			logger.error(e.getMessage());
		}
	}

	/**
	 * 添加文件
	 * @param in
	 * @param destFile
	 */
	private void appendFile(InputStream in, File destFile) {
		OutputStream out = null;
		try {
			// plupload 配置了chunk的时候新上传的文件append到文件末尾
			if (destFile.exists()) {
				out = new BufferedOutputStream(new FileOutputStream(destFile,
						true), BUFFER_SIZE);
			} else {
				out = new BufferedOutputStream(new FileOutputStream(destFile),
						BUFFER_SIZE);
			}
			in = new BufferedInputStream(in, BUFFER_SIZE);
			int len = 0;
			byte[] buffer = new byte[BUFFER_SIZE];
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
		} finally {
			try {
				if (null != in) {
					in.close();
				}
				if (null != out) {
					out.close();
				}
			} catch (IOException e) {
				logger.error(e.getMessage());
			}
		}
	}

	/**
	 * 文件下载
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequestMapping(value = "/plupload/download.do")
	@ResponseBody
	public void fileDownload(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String path = request.getParameter("filePath");
		String name = request.getParameter("fileName");
		String rootPath = request.getSession().getServletContext()
				.getRealPath("/");
		path = rootPath + path;
		
//		try {
//			path = rootPath + new String(path.getBytes("ISO-8859-1"), "utf-8");
//			name = new String(name.getBytes("ISO-8859-1"), "utf-8");
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		download(path, name, request, response);
	}

	/**
	 * 文件下载
	 * @param path
	 * @param name
	 * @param request
	 * @param response
	 * @return
	 */
	private HttpServletResponse download(String path, String name,
			HttpServletRequest request, HttpServletResponse response) {
		try {
			name = URLDecoder.decode(name, "utf-8");
			File file = new File(path);
			// 以流的形式下载文件。
			InputStream fis = new BufferedInputStream(new FileInputStream(path));
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();
			// 清空response
			response.reset();
			// 设置response的Header
			name = URLEncoder.encode(name, "utf-8");
			response.addHeader("Content-Disposition", "attachment;filename="
					+ name);
			response.addHeader("Content-Length", "" + file.length());
			OutputStream toClient = new BufferedOutputStream(
					response.getOutputStream());
			response.setContentType("application/octet-stream");
			toClient.write(buffer);
			toClient.flush();
			toClient.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return response;
	}
}